void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("HealthPickUp"))
{
m_CurrentHealth += amount;
other.gameObject.SetActive (false);
SetHealthUI ();
}
if (m_CurrentHealth <= 0f && !m_Dead)
{
OnDeath ();
}
}
trying to get it that if the tank hits the pick up item it will gain 20 pointa but as of right now ive got no clue what to do
To get collisions working in Unity, you need to do the following:
Attach a Collider component to each object you want to be part of the collision. This can be a BoxCollider, SphereCollider, etc. Whatever shape makes sense.
For trigger collisions (i.e. non-physics collisions), enable the Is Trigger value in the inspector on each collider component you created in step 1.
Attach a RigidBody component to the object you want to be colliding into other things. RigidBody components are expensive, and you don't want them all over the scene, so I would suggest you put it on your Tank. You may also have to turn on the Is Kinematic property, otherwise your Tank may behave improperly (it's hard to tell with such little information in your setup).
Attach a script to your Tank that has implemented the method OnTriggerEnter. An example is below.
(Optional, strongly recommended) I would suggest you create another script and attach it to your health pickup. I will demonstrate with an example below.
(Optional) You can use layer based collisions to filter what kinds of collisions you detect to make it more efficient.
public class Tank : MonoBehaviour
{
// Setup the initial health values in the editor.
[SerializeField] private int _initialHealth = 100;
[SerializeField] private int _maxHealth = 100;
private int _health = -1;
private void Awake()
{
_health = _initialHealth;
}
private void Update()
{
// You probably want to check this in Update, since you want the tank
// to die as soon as it happens, not just when you pick up a piece of health.
if (_health <= 0)
{
OnDeath();
}
}
private void OnDeath()
{
// Your death logic.
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("HealthPickup"))
{
// Get the HealthPickup component and then add the amount to the tank's
// health. This is more robust because you can now create HealthPickup
// objects with a variable amount of health.
HealthPickup healthPickup = other.gameObject.GetComponent<HealthPickup>();
if (healthPickup != null)
{
_health = Mathf.Clamp(_health + healthPickup.amount, 0, _maxHealth);
healthPickup.OnPickup();
}
}
}
}
public class HealthPickup : MonoBehaviour
{
[SerializeField] private int _amount = default;
public int amount { get { return _amount; } }
public void OnPickup()
{
Destroy(gameObject);
}
}
If you follow these steps, you should have collisions working and a flexible system for giving your Tank health pickups.
Related
Image1
Image2
I wanna make "btn_34" in [image2] to move "game39" class if user clicked "btn_21_2" in [image1]. If user didn't click "btn_21_2", Wanna make "btn_34" to move "game30". Which thing should I add or change in these pic?
Please post code and not images of code.
3 options: Quick, Standard, Best.
1-> Place public static boolean button21Flag = false; in your game17.class and when they click button btn_21_2 change it to true. When you get to btn_34.
if(game17.button21Flag)
intent = new Intent(game26.class,game39.class)
else
intent = new Intent(game26.class,game30.class)
2 -> Place an Extra into the Intent when btn_21_2 is clicked. And keep passing it, until you need it in btn_34.
btn_21_2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
Intent intent = new Intent(game17.class,game18.class);
intent.putExtra("button21Flag", true);
startActivity(intent);
}
});
// in btn_34 getIntent.getBooleanExtra("button21Flag", false);
3-> This solution is based on how complex and convoluted your code will get, if you keep approaching it this way.
Create a singleton called GameState and have it keep track of the game state. Anything you would like to keep track of should go in here and when you get to the point where you need it you can access it anywhere via a static context.
(EDIT) To respond to your answer.
public static boolean game17Flag = false;
btn_21_2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
game17Flag = true;
Intent intent = new Intent(game17.this, game18.class);
startActivity(intent);
}
});
//Remove this completely
{
if (btn_21_2.isPressed()) {
game17Flag = true;
}
}
I have a class with a member variable of type object. This object has a fixed number of fields. I'm trying to decide if I should use one setter function or multiple to mutate these fields.
To make the question more concrete, I've written the following class to model a simple organizational management structure in two different ways:
Multiple Setter Functions
class Management {
constructor() {
this.numberOfManagers = 100;
this.salaryDetails = {
regionalManagerSalary: 80000,
stateManagerSalary: 110000,
executiveManagerSalary: 200000
};
}
setRegionalManagerSalary(salary) {
this.salaryDetails.regionalManagerSalary = salary;
}
setStateManagerSalary(salary) {
this.salaryDetails.stateManagerSalary = salary;
}
setExecutiveManagerSalary(salary) {
this.salaryDetails.executiveManagerSalary = salary;
}
}
const management = new Management();
management.setRegionalManagerSalary(100000);
management.setStateManagerSalary(120000);
management.setExecutiveManagerSalary(210000);
One Setter Function
class Management {
constructor() {
this.numberOfManagers = 100;
this.salaryDetails = {
regionalManagerSalary: 80000,
stateManagerSalary: 110000,
executiveManagerSalary: 200000
};
}
setManagerSalary(typeOfManagerSalary, salary) {
this.salaryDetails[typeOfManagerSalary] = salary;
}
}
const management = new Management();
management.setManagerSalary('regionalManagerSalary', 100000);
management.setManagerSalary('stateManagerSalary', 120000);
management.setManagerSalary('executiveManagerSalary', 210000);
Would implementation 1. be better or would implementation 2. be better?
I will always consider the higher readability approach if it doesn't trade off a lot of writability. The second one is more generic but the first one is more clear.
So I think the first one is better as it is more clear that there are only 3 fields in salaryDetails. Just consider you are not the author and when you see the second one, you have no idea how many fields there will be in salaryDetails as someone could just call management.setManagerSalary('someNewSalary', 100000); somewhere to add some new fields.
Unless you have more than one Management objects and each of them might have some specific fields under salaryDetails, I don't think the second approach is better.
My recommendation would be to have one method say setSalaryDetails which will take salary object as input which you can set directly. Something like -
setSalaryDetails(salaryDetails){this.salaryDetails = salaryDetails; }
When you invoke this method you can appropriately create this object with those fields set that you will pass to it.
It is better to not have any setter at all. Initialize all the required properties in the constructor (let the constructor require arguments for this).
The code you posted it not OOP but procedural code under disguise. If you want to make it OOP then the code must stay where the data is, i.e. in the class.
As a first improvement step, your code should look like this:
class Management {
constructor(nb, regionalSalary, stateSalary, executiveSalary) {
this.numberOfManagers = nb;
this.salaryDetails = {
regionalManagerSalary: regionalSalary,
stateManagerSalary: stateSalary,
executiveManagerSalary: executiveSalary
};
}
}
const management = new Management(100, 100000, 120000, 210000);
Shorter, much cleaner, less error prone.
The fragment you posted is not enough to tell what you want to achieve but the new signature of the constructor tells me that you are mixing too many responsibilities into a single class.
A cleaner design is to use separate classes for each manager type:
/* abstract */ class Manager {
constructor(salary) {
this.salary = salary;
}
}
class RegionalManager extends Manager { }
class StateManager extends Manager { }
class ExecutiveManager extends Manager { }
class Management {
constructor(nb, regionalManager, stateManger, executiveManager) {
this.numberOfManagers = nb;
this.managers = {
regionalManager: regionaManager,
stateManager: stateManager,
executiveManager: executiveManager
};
}
}
const management = new Management(
100,
new RegionalManager(100000),
new StateManager(120000),
new ExecutiveManager(210000)
);
You can now implement the logic common to all manager types in class Manager, the logic that is specific to each manager type in its class and the logic that handles the managers by number, without caring about their individual characteristics, in class Management. This way the code uses less if and switch conditions, is easier to read, understand and develop further.
all. I have kind of a doozy of a problem, that could be solved really simply, if I just wanted to duplicate the code. I mean, really, it's a small part of a project that I'm doing just to see if I can, more than anything else, but it is bothering me since I've thought it up.
The Project
For fun, I've decided to take someone's ActionScript 3, text-based game engine and convert it to TypeScript and ultimately JavaScript using PixiJS.
The thing is, there are still 20213 errors to be fixed running tsc, so I could just leave this to a later date. But I was working on the Button class, which they defined as a subclass of MovieClip. That's fine; I just responded by reading up on PIXI buttons, and they seem fairly straightforward. Just, in the button's constructor, add something akin to the following lines:
export class Button extends PIXI.Sprite {
private _callback : Function;
private _height : number;
private _width : number;
public get callback() : Function { return this._callback; }
public set callback(fn : Function) {this._callback = fn; }
public get height() : number { return this._height; }
public set height(h : number) {this._height = h; }
public get width() : number {return this._width; }
public set width(w : number) {this._width = w; }
public constructor(width = 180, height = 90, callback: Function = null){
super(new PIXI.Texture(new PIXI.BaseTexture(GLOBAL.BTN_BACK, PIXI.SCALE_MODES.NEAREST)));
this.callback = callback;
this.width = width;
this.height = height;
this.buttonMode = true;
this.interactive = true;
this.anchor.set(0.5);
this.on('mousedown', this.callback)
.on('touchstart', this.callback);
}
}
That's a bit of a simplified version, and the version I did on Codepen uses a Container and a private _sprite field instead (as well as a ColorMatrixFilter that doesn't work too well on the black icons I picked out, but that's not really important for this question), but that's roughly the gist of how it's done.
The Problem
The problem is that, in the codepen, I'd like to do the following:
// assign `this.callback` to each of the following events:
let that = this;
['click','mousedown','touchstart'].map(evt => that.on(evt, that.callback});
with a simple call being passed in their constructors elsewhere:
for (let n = 0; n < 5; ++n){
btnArray.push(new Button(16, 16, () => console.info('You pushed button %d', n)));
}
but I'm not getting anything from them, even in the Chrome Console. I even logged that ColorMatrixFilter I mentioned earlier, to see if it was console.info that was wrong. Nope. So now, I'm confused on that. I was hoping to be able to just make a GLOBAL (a legacy static object from the AS source) key to iterate through for the events, but it looks like that's not happening.
The Questions
Is what I'm trying to do feasible, if odd? Is it blocked by a security feature (for which I'd be grateful)? If not, what am I doing wrong?
Should I even worry about setting all these different event handlers, or is just listening to click enough?
When an arrow function like your event map is executed the this context is not set, so any code that references this is going to get the current value, including any functions your map calls.
Replace your event map with the following:
['click','mousedown','touchstart'].map(function(evt) { that.on(evt, that.callback} } );
A demonstration:
function Named(x) {
this.name = x;
}
var foo = new Named("foo");
var bar = new Named("bar");
var showFunc = function show() {
// this is context dependant
console.log(this.name);
}
var showArrow;
// this is the window
showArrow = () => console.log(this.name);
var fooShowArrow;
(function() {
// this is foo
that = this;
fooShowArrow = () => console.log(that.name);
}).apply(foo);
var example = function(func) {
// For the demo, at this point, this will always be bar
func.apply(this, [ "arbitrary value" ]);
}
// explicitly set the current "this" to bar for the execution of these functions
example.apply(bar, [showFunc]); // works
example.apply(bar, [showArrow]); // fails, this is still the window
example.apply(bar, [fooShowArrow]); // fails, this is still foo
I've started learning QML recently (after trying it out a long time ago) and I'm stuck at the way Qt C++ code interacts with QML and vice versa.
I have a Counter which has the following header:
#include <QObject>
#include <QTimer>
class Counter : public QObject
{
Q_OBJECT
Q_PROPERTY(int count
READ getCount
WRITE setCount
NOTIFY signalCountChanged)
public:
Counter(QObject *parent = Q_NULLPTR);
int getCount();
void setCount(int count);
signals:
void signalCountChanged(int);
public slots:
void slotStart();
private slots:
void slotTimeout();
private:
int count;
QTimer *timer;
};
My main.cpp is as follows:
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlContext>
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
#include "counter.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Counter>("org.qmlplayground.counter", 0, 1, "Counter");
QQuickView view;
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
QObject *viewO = dynamic_cast<QObject*>(view.rootObject());
Counter c;
// Register Counter instance as "counter" property of top level context so that it can be accessed from within the QML code (for example: set the value count)
view.rootContext()->setContextProperty("counter", &c);
QObject::connect(viewO, SIGNAL(signalStartCounter()),
&c, SLOT(slotStart()));
QObject::connect(viewO, SIGNAL(signalQuit()), &app, SLOT(quit()));
view.show();
return app.exec();
}
and finally part of my QML (the main.qml which is loaded in the QQuickView while the rest being an UI form):
import QtQuick 2.7
import QtQuick.Window 2.2
// Importing some JavaScript files
import "qrc:/loggingFunctions.js" as LOG
import "qrc:/parseFunctions.js" as PARSE
// Importing a Qt C++ custom module
import org.qmlplayground.counter 0.1
MainForm {
property int countState: counter.count // ERROR HERE
signal signalStartCounter()
signal signalQuit()
anchors.fill: parent
textInputMouseArea.onClicked: {
LOG.logger("Clicked! Selecting all text in text input field", "N")
textInput.selectAll()
}
textInput.onAccepted: {
if(textInput.text === "quit") signalQuit()//Qt.quit();
if(textInput.text === "help") textInput.text = LOG.logger("Displaying help", "H");
var res = PARSE.parseInput(textInput.text);
if(res && (typeof res === 'object') && res.constructor === Array) {
switch(res[0]) {
case "fact":
labelOutput.text = res[1];
break;
case "count":
counter.count = res[1];
signalStartCounter();
break;
}
}
}
onCountStateChanged:
console.log("Hello")
textInput.onTextChanged:
console.log("Text changed");
}
As you can see I've already tested two signals sent from my QML to my C++ code one being connected to my QGuiApplication's slot quit() and the other being connected to my counter's slot slotStart(). It works fine. It seems that the line
counter.count = res[1];
doesn't cause any issues (perhaps because it's JS and not QML?). Now I want to read the count value of my Counter instance and update my UI accordingly. If I'm not mistaken every QML property automatically gets a couple of things one of these being the onChanged method (event handler or whatever it's called).
When I run my code however I get
`qrc:/main.qml:21: ReferenceError: counter is not defined
I thought that doing view->rootContext()->setContextProperty("counter", &c); would be enough but it seems that I'm missing something. So the more general question would be how do I properly make a C++ object visible in QML context.
This took me perhaps 2 hours to figure out (I posted my question when I was on the verge of commiting a suicide :D) but the answer was really obvious: how can I call for a property which hasn't been initialized yet? The solution to my problem is basically to move the setContextProperty() BEFORE I load the QML file:
// ...
QQuickView view;
Counter c;
view.rootContext()->setContextProperty("counter", &c);
view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
// ...
By doing so the property is first added to the root context of the view and after that the additional QML stuff is loaded but the counter property is still present). With the previous version of my code I was basically trying to access counter inside my QML file BEFORE I have added it as a property.
I have a script called Death which re spawns the player at the beginning location when the collision is true. I am trying to make a score count that when this collision is true it will minus 100 points but have been unsuccessful. The script bellow if from the score and death script. Any help would be much appreciated.
Score script:
var gui : GameObject;
static var score : int;
Death.death = false;
function Start ()
{
gui.GetComponent ("GUIText").text = "Score: 0";
}
function Update ()
{
gui.GetComponent ("GUIText").text = "Score: " + score;
if (death)
{
score = score - 100;
}
}
Death Script:
#pragma strict
var Ball : Transform;
public var death : boolean = false;
function OnCollisionEnter (b : Collision)
{
if (b.gameObject.tag == "Ball")
{
death = true;
Ball.transform.position.x = 1.6;
Ball.transform.position.y = 1.5;
Ball.transform.position.z = 1.1;
Ball.GetComponent.<Rigidbody>().velocity.y = 0;
Ball.GetComponent.<Rigidbody>().velocity.x = 0;
Ball.GetComponent.<Rigidbody>().velocity.z = 0;
}
}
I hope, that I can help you even though I'm using C#. It should be very easy to translate this to UnityScript.
using UnityEngine;
public class Score : MonoBehaviour
{
public GUIText guiText;
int score;
void Update()
{
if(DeathTrigger.wasTriggered)
{
DeathTrigger.wasTriggered = false;
score -= 100;
}
guiText.text = string.Format("Score: {0}", score);
}
}
public class DeathTrigger : MonoBehaviour
{
public static bool wasTriggered;
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ball"))
{
wasTriggered = true;
// ...
}
}
}
I assume this is a beginner's questions, so I won't say anything about how static variables are evil and so on, but I still want to post an example of where to go next for a better approach:
using System;
using UnityEngine;
using UnityEngine.UI;
public class BetterDeathTrigger : MonoBehaviour
{
// This event will be called when death is triggered.
public static event Action wasTriggered;
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ball"))
{
// Call the event.
if (wasTriggered != null)
wasTriggered();
// ...
}
}
}
public class BetterScore : MonoBehaviour
{
public Text uiText; // Unity 4.6 UI system
int score;
void Start()
{
// Subscribe to the event.
BetterDeathTrigger.wasTriggered += WasTriggered_Handler;
}
// This method will now be called everytime the event is called from the DeathTrigger.
private void WasTriggered_Handler()
{
score -= 100;
uiText.text = string.Format("Score: {0}", score);
}
}
A couple of things:
GUIText is pretty old and was already replaced by the new UI system since Unity version 4.6
Static variables are not smart in the long run, prefer instances of objects unless you are very sure how statics work
This is good example of where to use events. Again, it being static might lead to problems but for the first example it's the easiest.
The Unity Learn site offers a lot of tutorials about programming concepts such as "Communicating between scripts", they also have basic game examples where you can follow along with a complete project.
It's definitely worth trying what Xarbrough suggested to go with instead. Statics can be confusing and get in the way in the long run. But here's how you can do it, written in Javascript.
public class Death { // you can change the class name to something that is broad enough to hold several public static variables
public static var death : boolean;
}//This will end this class. When you make public classes like this, the script doesnt even need to be attached to a object, because it doesn't use Mono behavior
//This would be the actual DeathScript, whats above is technically not part of the Death script
var Ball : Transform;
function OnCollisionEnter (b : Collision) {
if (b.gameObject.tag == "Ball"){
Death.death = true;
Ball.transform.position.x = 1.6;
Ball.transform.position.y = 1.5;
Ball.transform.position.z = 1.1;
Ball.GetComponent.<Rigidbody>().velocity.y = 0;
Ball.GetComponent.<Rigidbody>().velocity.x = 0;
Ball.GetComponent.<Rigidbody>().velocity.z = 0;
} }
From there, anytime you want to access the static variable, just tell it where to look. Death.death.
Hope this helps!