Trying to do collisions between two different classes - class

Sorry I'm not posting my code in here but the format was screwing up and it wouldn't post properly. I'm trying to make a game in which the player controls a ship and asteroids move in from the right side of the screen and the player has to avoid them. For the life of me I can;t figure out how to get the asteroids to collide with the player causing the player to lose and could use some assistance.
My Code for my game

You're pretty close.
In the function move() you calculate the new x and y position of the player:
void move() {
int r = d>>1;
sx = constrain(sx + v*(int(isRight) - int(isLeft)), r, width - r);
sy = constrain(sy + v*(int(isDown) - int(isUp)), r, height - r);
}
Next you have you check if the player position is in the bounds of the asteroid.
This is from you code in the Display() function:
void display() {
image(ship, sx, sy, 100, 50);
if (sx > a1x && sx < a1x && sy > a1y && sy < a1y){
image(explo, sx, sy, 200, 200);
}
This is in the right direction, but checks if both x and y of the player and the asteroid match exactly. This is very improbable, because it is the exact corner of both the player and the asteroid. Besides, the player might move more than 1 pixel per frame, causing it to skip the trigger.
Instead try this:
if (sx > a1x && sx < a1x +asteroid.aw && sy > a1y && sy < a1y+asteroid.ah)
This will check if the player x/y is in the bounds of the asteroid. And should get the result you want. However, this does not yet account for the height/width of the player spaceship. So you should also check
if (sx+player.width > a1x && sx+player.width< a1x +asteroid.aw && sy+player.height> a1y && sy+player.height< a1y+asteroid.ah)
Lastly I would make a general comment on your code. There is a lot of repetition. I assume you're learning, so that's okay, but allow me to give you some pointers that will make writing code a lot simpler: using ArrayLists and extending the use of objects
ArrayList<Asteroid> List_Of_Asteroids = new ArrayList<Asteroid>();
List_Of_Asteroids.add(new Asteroid(random(X1,X2), random(Y1,Y2))
This creates a list where you can add or delete asteroid objects. This makes it easy to do the same action for all asteroid, because you only have to type it once. Makes for less code as well. For instance:
player.move();
for (Asteroid rock : List_Of_Asteroids){
if (player.collisionCheck(rock)){
gameOver(); //triggers explosion image and subtracts life / ends game
}
}
display();
Just 5 lines to check all asteroids, even if there are 100. Everything that has to do with objects should be written in the object themselves. In your code the x/y position of the asteroids are kept in the main loop. You can easily divert those to the objects. If you look at the two code fragments above, you can access the asteroid x/y like this (inside the player class):
boolean collisionCheck(Asteroid a){
if (x > a.ax && x < a.ax+a.aw && y > a.ay && y < a.ay+a.ah){
return true;
else{
return false;}
Hope it helps!

Related

Is there a better way to write this top down car mdoel

I Am writing a top down car drift game, where i want to make the car move in a circle and user controls the radius of the circle with the steering, basically straight steering is a straight line and turned left is a small circle to the left of the car which it will follow. as the car turns more (either side) i try to make the cars front turn more and more towards the centre, as if its drifting.
Am using unity and this is how i though i should design the model.
This is for a mobile game. so i have written a steering controller for the car, to control its left and right, the speed is constant.
There are two rigid bodies.
The front white coloured box and the big grey coloured box both are rigid bodies. connected with a hinge joint.
The front box on every frame rotate a certain amount of degrees on it own z axis and moves a little forward. Thus follows a circle shape. how much is rotates is determined my the steering.
I Can make both the bodies kinematic and make sure they follow a circle shape and move that way, but i also want appropriate behaviour during collisions, In the final plan there can be all kinds of collisions. So i made them kinematic and added velocities using add force methods. On it's own the front box is perfect, It rotates in circle as i change the steering the circle gets bigger everything is fine, But when i add the Other chassis box, the forces are all messed up. centrifugal forces, and the inertia messes everything.
Basically i need the car to drift is perfect circles and user should be able to control the radius of the circle. What is the best way to model this.
Here is the code for both the rigid bodies.
the front box code. This is just the fixed update method. Please ignore the controls related code. It'e unnecessary so i left it out.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle -= 45;
//-------------------------
// S P E E D.
//-------------------------
current_speed = Utils.curve_map_linear(0, 45, min_speed, max_speed, Mathf.Abs(current_steering_angle), -1);
_rigid_body.AddRelativeForce(acceleration * Vector3.up);
velocity = transform.InverseTransformVector(_rigid_body.velocity);
if(velocity.y > current_speed){
velocity.y = current_speed;
}
// to prevent reverse movement due to centrifugal force.
velocity.x = 0;
//-------------------------
// R O T A T I O N.
//-------------------------
current_radius = Mathf.Sign(current_steering_angle) * Utils.exp_range_3(0, 45, min_radius, max_radius, Mathf.Abs(current_steering_angle), steering_tension, -1);
current_rot_rate = (velocity.y / (2 * Mathf.PI * current_radius)) * 360;
Vector3 angle = transform.localEulerAngles;
angle.z += (current_rot_rate * Time.fixedDeltaTime);
transform.localEulerAngles = angle;
//-------------------------
// A P P L Y.
//-------------------------
_rigid_body.velocity = transform.TransformVector(velocity);
}
The Utils.exp_linear and exp_range functions are just range to range mappers with some tension, to control the sensitivity of the steering on the controls.
Code for the chassis.
{
//-------------------------
// I N I T.
//-------------------------
current_steering_angle = controls_i.ToSignedRotation(controls_i.getSteeringAngle());
current_steering_angle = (current_steering_angle < 0) ? (current_steering_angle + 90): current_steering_angle;
current_steering_angle = current_steering_angle - 45;
current_steering_angle = ((float)((int)(current_steering_angle * Mathf.Pow(10, 5))))/Mathf.Pow(10,5);
//-------------------------
// R O T A T I O N.
//-------------------------
current_angle = front_transform.eulerAngles.z - _rigid_body.transform.eulerAngles.z;
current_angle = (Mathf.Abs(current_angle) > 180) ? ((Mathf.Abs(current_angle) - 360) * Mathf.Sign(current_angle)) : current_angle;
current_angle += Mathf.Sign(current_steering_angle) * Utils.curve_map_linear(0, 45, min_angle, max_angle, Mathf.Abs(current_steering_angle), 1);
_rigid_body.transform.RotateAround(front_transform.position, Vector3.forward, current_angle);
//-------------------------
// S P E E D.
//-------------------------
Vector3 velocity = _rigid_body.transform.InverseTransformVector(_rigid_body.velocity);
if (velocity.y < 0){
velocity.y = 0;
}
_rigid_body.velocity = _rigid_body.transform.TransformVector(velocity);
}
I would like to know how to actually implement something like this in unity. I am new to this unity stuff. I looked all over and there was a lot of stuff for 3d cars but not much on top down ones. Appreciate any kind of feedback.
Make it non kinematic, remove the rigidbody of the front tires and make the front tires a child of the chassis.
Handling position:
Make a method that looks at the car's current position, how much the player is turning, and returns the tangential velocity the car needs to go to drive in the appropriate circle:
Vector2 GetTangentialVelocity(...) { }
Then, find the difference between that velocity and the current velocity of the chassis:
Vector2 velDiff = GetTangentialVelocity(...) - chassis_rigidbody.velocity;
Then, apply that difference using AddForce with ForceType.VelocityChange:
chassis_rigidbody.AddForce(velDiff, ForceType.VelocityChange);
Handling rotation:
Move the center of mass forward. You can do this by making the rigidbody long and put the collider at the rear of the object, or by setting RigidBody.centerOfMass:
chassis_rigidbody.centerOfMass = Vector2.up * 0.5;
Make a function similar to GetTangentialVelocity that returns the desired angular velocity, find the difference from chassis_rigidbody.angularVelocity, then use AddTorque with ForceType.VelocityChange:
Vector2 angVelDiff = GetAngularVelocity(...) - chassis_rigidbody.angularVelocity;
chassis_rigidbody.AddTorque(angVelDiff , ForceType.VelocityChange);

Need to rotate object in specific ways - Stuck with Gimbal Lock?

I am working on a small mini-game that requires the rotation of a cube 90 degrees in the appropriate direction based on the direction you swipe. So you could swipe up and it would rotate up 90 degrees, and them immediately after, swipe left, and it would swipe 90 degrees to the left from your current rotation (so it would stay rotated up 90 degrees as well). I feel like this should be really simple, but it's giving me a ton of trouble.
I would like to use Lerp/Slerp so that the rotation looks nice, though it isn't entirely necessary. The way I currently have it implemented, each time I call my "SlerpRotateLeft()" function for example, it only rotates to the exact same exact rotation relative to the world each time (instead of the current rotation + 90 degrees in the correct direction).
I have been reading up on Quaternions and Euler angles all day, but I'm still not entirely sure what my problem is.
I am currently using states to determine when the object is currently rotating and in what direction, though I feel like I may be overcomplicating it. Any possible solution to this problem (where you can swipe in a particular direction, in any order, in succession, to rotate a cube 90 degrees in that particular direction). Previously, I attempted to use coroutines, but those didn't have the desired effect either (and I was unable to reset them).
Here is my class. It works and you can test it by dropping the script into any cube object in-editor, but it doesn't work as intended. You will see what my problem is by testing it (I recommend placing an image on the cube's front face to track which one it is). I'm not sure if I explained my problem properly, so please let me know if any more information is needed.
****UPDATE: I have accepted #Draco18s's answer as correct, because their solution worked. However, I did not completely understand the solution, or how to store the value. I found an answer to a similar question that also used Transform.Rotate, and stored the value, which helped clear the solution up. The key seemed to be storing it in a GameObject instead of in a Quaternion like I originally thought. I thought I should provide this code in case anyone stumbles upon this and is equally confused, though you may not need the swipe detection:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotater : MonoBehaviour
{
private GameObject endRotation;
//SWIPE VARIABLES
public Vector2 touchStart = new Vector2(0, 0);
public Vector2 touchEnd = new Vector2(0, 0);
public Vector2 currentSwipe = new Vector2(0, 0);
public Vector2 currentSwipeNormal = new Vector2(0, 0);
// Use this for initialization
void Start()
{
endRotation = new GameObject();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//Debug.Log("Touched at: " + touchStart);
}
if (Input.GetMouseButtonUp(0))
{
touchEnd = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
//Get Swipe Vector information
currentSwipe = new Vector2(touchEnd.x - touchStart.x, touchEnd.y - touchStart.y);
//Normalize Swipe Vector
currentSwipeNormal = currentSwipe;
currentSwipeNormal.Normalize();
//Swipe up
if (currentSwipeNormal.y > 0 && currentSwipeNormal.x > -0.5 && currentSwipeNormal.x < 0.5)
{
endRotation.transform.Rotate(-Vector3.left, 90, Space.World);
}
//Swipe down
if (currentSwipeNormal.y < 0 && currentSwipeNormal.x > -0.5 && currentSwipeNormal.x < 0.5)
{
endRotation.transform.Rotate(Vector3.left, 90, Space.World);
}
//Swipe left
if (currentSwipeNormal.x < 0 && currentSwipeNormal.y > -0.5 && currentSwipeNormal.y < 0.5)
{
endRotation.transform.Rotate(Vector3.up, 90, Space.World);
}
//Swipe right
if (currentSwipeNormal.x > 0 && currentSwipeNormal.y > -0.5 && currentSwipeNormal.y < 0.5)
{
endRotation.transform.Rotate(-Vector3.up, 90, Space.World);
}
}
LerpRotate();
}
void LerpRotate()
{
transform.rotation = Quaternion.Lerp(transform.rotation, endRotation.transform.rotation, Time.deltaTime * 10);
}
}
Use Transform.RotateAround
You're encountering an issue where you take the current Euler angles and try and add/subtract 90, which does not necessarily correlate to the desired position, due to the rotated nature of the rotated reference frame.
But using RotateAround, you can pass in the global Up, Left, and Forward vectors, which is what you're trying to do.

Drag to add power, release to throw at opposite angle (RigidBody2D), strange beahviour

I'm a total beginner and I'm making a simple 2D game, you have ball which you throw to collect pickups. I managed, following tutorials and searching on the web, to script the controls as I wanted them, when the mouse is clicked the force to apply is calculated by the movement on axis X and Y and on mouse button release the force is applied and the gravity turned on:
if (Input.GetMouseButton(0))
{
mouseDown = true;
}
if (!Input.GetMouseButton(0))
{
mouseDown = false;
}
if (Input.GetAxis("Mouse X") != 0 && mouseDown)
{
xForce -= Input.GetAxis("Mouse X") * 50;
}
if (Input.GetAxis("Mouse Y") != 0 && mouseDown)
{
yForce -= Input.GetAxis("Mouse Y") * 50;
}
if (Input.GetMouseButtonUp(0))
{
GetComponent<Rigidbody2D>().gravityScale = 1;
GetComponent<Rigidbody2D>().AddForce(new Vector2(xForce, yForce));
yForce = 0;
xForce = 0;
}
But while working perfectly while testing it on unity using the mouse, it behave strangely on my 2 android phones. Sometimes the ball seems to get the force only for the X axis, and even if dragging only vertically the ball has an X force applied... What could be the problem?
EDIT: I added Debug.Log(xForce) and Debug.Log(yForce) and looking at the log with adb logcat I noticed that, also when simply tapping on the screen, without dragging on neither axis, the value of those variables increase, I have really no idea on how to solve this...
Personally I would make this easier on myself by just using Input.GetMouseButtonDown and Input.GetMouseButtonUp instead. The below method will return identical results on all platforms.
On down, set a variable like "startFirePosition = worldPosOfInput".
On up, "newForce = worldPosOfInput - startFirePosition"
You can find the world position of the input by using Input.mousePosition and Camera.ScreenToWorldPoint.
Your newForce Vector2 now contains information like the drag distance (magnitude), and firing direction that you can use in your firing code.
You can assign newForce directly to your rigidbody, or tweak it first to do things like increase the magnitude, clamp direction, etc.
PS, if needed you can flip the direction your newForce will take the rigidbody by flip flopping the line "worldPosOfInput - startFirePosition" to "startFirePosition - worldPosOfInput".

HLSL Unity5> Multiple render targets

I am attempting to specify a frag output into a set texture (render target) depending on some logic.
To summarise my shader:
I am preforming a Texture3D raycasting method that allows for the user to 'see' inside the texture 3D data.
My issue arises when wanting to sample an area of this main texture and dump it into another of a smaller resolution (allowing for an eventual 'zooming' affect)
My research thus far has brought me to the use of Multiple render targets . in that (to my understanding) I would send this frag function output to another function which then outputs to set different targets.
Feedback appreciated;especially if there is an easier way to sample area into another texture (I have tried various compute shader methods- CPU methods are too slow) a CPU based analogy being the Unity's:
GetPixels function
Extract:
.float alpha is actually a raycast step result
.float4 t the colour plus alpha at mapping of the input Texture3D
._sample a pseudo bool flag for sampling
.texture3Dsampler (within commented if statement) is the smaller resolution Texture3D that I wish to write to; given the pixel being evaluated of the input Texture3D is within texture3Dsampler bounds from a certain start point - as shown in if statement logic.
float a = (1 - alpha);
float4 t = float4(t3d, a);
//Cn = Current pixel
int Cx = start.x;
int Cy = start.y;
int Cz = start.z;
if(_sample == 1 &&
((Cx >= _XSS) && (Cx <= (_XSS+_Tex3DSampled.x))) &&
((Cy >= _YSS) && (Cy <= (_XSS+_Tex3DSampled.y))) &&
((Cz >= _ZSS) && (Cz <= (_YSS+_Tex3DSampled.z)))
)
{
//render t into BOTH texture3D to screen output and texture3Dsampler output
}
else //if not sampling into other Texture3d, simple return to render t onto screen
{
return t; //returning into t
}
}

iPhone SDK: Collision detection, does it have to be a rectangle?

I am making a basic platform game for the iPhone and I have encountered a problem with my collision detection.
if (CGRectIntersectsRect(player.frame, platform.frame))
pos2 = CGPointMake(0.0, +0.0);
else
pos2 = CGPointMake(0.0, +10.0);
The collision detection is to stop in-game-gravity existing when the player is on a platform, the problem is with the fact that the collision detection is the rectangle around the player, is there anyway to do collision detection for the actual shape of an image (with transparency) rather that the rectangle around it?
You'll have to program this on your own, and beware the pixel-by-pixel collision is probably too expensive for the iPhone. My recommendation is to write a Collidable protocol (called an interface in every other programming language), give it a collidedWith:(Collidable *)c function, and then just implement that for any object that you want to allow collision for. Then you can write case-by-case collision logic. Similarly, you can make a big superclass that has all the information you'd need for collision (in your case either an X, Y, width, and height, or an X, Y, and a pixel data array) and a collidesWith method. Either way you can write a bunch of different collision methods - if you're only doing pixel collision for a few things, it won't be much of a performance hit. Typically, though, it's better to do bounding box collision or some other collision based on geometry, as it is significantly faster.
The folks over at metanetsoftware made some great tutorials on collision techniques, among them axis separation collsion and grid based collision, the latter of which sounds like it would be more viable for your game. If you want to stick with brute force collision detection, however (checking every object against every other object), then making a bounding box that is simply smaller than the image is typically the proper way to go. This is how many successful platformers did it, including Super Mario Brothers.You might also consider weighted bounding boxes - that is, you have one bounding box for one type of object and a different sized one for others. In Mario, for example, you have a larger box to hit coins with than you do enemies.
Now, even though I've warned you to do otherwise, I'll oblige you and put in how to do pixel-based collision. You're going to want to access the pixel data of your CGImage, then iterate through all the pixels to see if this image shares a location with any other image. Here's some code for it.
for (int i = 0; i < [objects count]; i++)
{
MyObject *obj1 = [objects objectAtIndex:i];
//Compare every object against every other object.
for (int j = i+1; j < [objects count]; j++)
{
MyObject *obj2 = [objects objectAtIndex:j];
//Store whether or not we've collided.
BOOL collided = NO;
//First, do bounding box collision. We don't want to bother checking
//Pixels unless we are within each others' bounds.
if (obj1.x + obj1.imageWidth >= obj2.x &&
obj2.x + obj2.imageWidth >= obj1.x &&
obj1.y + obj1.imageHeight >= obj2.y &&
obj2.y + obj2.imageGeight >= obj1.y)
{
//We want to iterate only along the object with the smallest image.
//This way, the collision checking will take the least time possible.
MyObject *check = (obj1.imageWidth * obj1.imageHeight < obj2.imageWidth * obj2.imageHeight) ? obj1 : obj2;
//Go through the pixel data of the two objects.
for (int x = check.x; x < check.x + check.imageWidth && !collided; x++)
{
for (int y = check.y; y < check.y + check.imageHeight && !collided; y++)
{
if ([obj1 pixelIsOpaqueAtX:x andY:y] && [obj2 pixelIsOpaqueAtX:x andY:y])
{
collided = YES;
}
}
}
}
}
}
I made it so pixelIsOpaque takes a global coordinate rather than a local coordinate, so when you program that part you have to be careful to subtract the x and y out of that again, or you'll be checking out of the bounds of your image.